package com.yuong.demo.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.yuong.demo.DensityUtil;

import androidx.annotation.Nullable;

/**
 * 〈纵向滚动柱状图〉
 *
 * @author yuandong
 * @create 2021/4/28
 * @since 1.0.0
 */
public class VerticalBarChartView extends View {
    private int width;
    private int height;
    private float paddingTop;
    private float paddingBottom;
    private float paddingLeft;
    private float paddingRight;

    private float lineWidth;
    private float maxTitleWidth, maxValueWidth;
    private float textSize;

    private Paint linePaint;
    private Paint titlePaint;
    private Paint valuePaint;
    private Paint barPaint;
    private Paint valueBarPaint;
    private Paint whitePaint;

    private Paint.FontMetrics titleFontMetrics;
    private Paint.FontMetrics valueFontMetrics;

    private float titleMarginRight;
    private float valueMarginLeft;
    private float xTitleMarginTop;

    private float barWidth;
    private float barInterval;
    private float barPaddingStart;
    private float barPaddingEnd;

    private float xWidth, yWidth;

    private String[] titles = {"大运中心", "南山文体", "贵港体育", "崇左体育", "崇左体育", "武汉体育", "长沙中心", "北京鸟巢", "罗湖网球"};
    private int[] values = {8000, 9000, 10000, 15000, 10000, 20000, 25000, 18000, 30000};
    private String[] xTitles = {"5000", "10000", "15000", "20000", "25000"};

    private int[] colors = new int[]{Color.parseColor("#FFE8B6ED"), Color.parseColor("#FF92D1FF")};

    private float barTotalHeight;
    private float scrollY;//竖直滑动距离
    private float lastY;
    private float factor = 0.75f;

    public VerticalBarChartView(Context context) {
        this(context, null);
    }

    public VerticalBarChartView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public VerticalBarChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        paddingTop = DensityUtil.dp2px(getContext(), 20);
        paddingBottom = DensityUtil.dp2px(getContext(), 20);
        paddingLeft = DensityUtil.dp2px(getContext(), 10);
        paddingRight = DensityUtil.dp2px(getContext(), 10);
        lineWidth = DensityUtil.dp2px(getContext(), 1);
        textSize = DensityUtil.sp2px(getContext(), 11);

        titleMarginRight = DensityUtil.dp2px(getContext(), 10);
        valueMarginLeft = DensityUtil.dp2px(getContext(), 10);
        xTitleMarginTop = DensityUtil.dp2px(getContext(), 6);

        barPaddingStart = DensityUtil.dp2px(getContext(), 10);
        barPaddingEnd = DensityUtil.dp2px(getContext(), 10);
        barWidth = DensityUtil.dp2px(getContext(), 10);
        barInterval = DensityUtil.dp2px(getContext(), 15);


        linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        linePaint.setStyle(Paint.Style.FILL);
        linePaint.setStrokeWidth(lineWidth);
        linePaint.setColor(Color.parseColor("#E9E9E9"));

        titlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        titlePaint.setStyle(Paint.Style.FILL);
        titlePaint.setTextSize(textSize);
        titleFontMetrics = titlePaint.getFontMetrics();

        valuePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        valuePaint.setStyle(Paint.Style.FILL);
        valuePaint.setTextSize(textSize);
        valueFontMetrics = valuePaint.getFontMetrics();

        barPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        barPaint.setStyle(Paint.Style.STROKE);
        barPaint.setStrokeWidth(barWidth);
        barPaint.setColor(Color.parseColor("#ECECEC"));

        valueBarPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        valueBarPaint.setStyle(Paint.Style.STROKE);
        valueBarPaint.setStrokeWidth(barWidth);


        whitePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        whitePaint.setStyle(Paint.Style.FILL);
        whitePaint.setColor(Color.WHITE);

        initMaxTitleWidth();
        initMaxValueWidth();
        initBarContentHeight();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = MeasureSpec.getSize(widthMeasureSpec);
        height = MeasureSpec.getSize(heightMeasureSpec);
        xWidth = width - paddingLeft - paddingRight - maxTitleWidth - titleMarginRight - valueMarginLeft - maxValueWidth;
        yWidth = height - paddingTop - paddingBottom - textSize - xTitleMarginTop - lineWidth;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        float startX = paddingLeft + maxTitleWidth + titleMarginRight;
        //画纵向线
        float space = xWidth / 6f;
        for (int i = 0; i < 5; i++) {
            float x = (i + 1) * space + startX;
            float y = height - paddingBottom - textSize - xTitleMarginTop - lineWidth;
            float y1 = y - yWidth;
            canvas.drawLine(x, y, x, y1, linePaint);
        }

        //画条形图
        drawBar(canvas);

        //画遮挡空白
        //底部遮挡空白
        float whiteWidth = paddingBottom + textSize + xTitleMarginTop + lineWidth;
        whitePaint.setStrokeWidth(whiteWidth);
        float whiteY = height - whiteWidth * 0.5f;
        canvas.drawLine(0, whiteY, width, whiteY, whitePaint);
        //顶部遮挡空白
        whitePaint.setStrokeWidth(paddingTop);
        canvas.drawLine(0, paddingTop * 0.5f, width, paddingTop * 0.5f, whitePaint);


        //画x轴
        float endX = width - paddingRight - maxValueWidth - valueMarginLeft;
        float startY = height - paddingBottom - textSize - xTitleMarginTop - lineWidth * 0.5f;
        canvas.drawLine(startX, startY, endX, startY, linePaint);

        //画x轴标题
        for (int i = 0; i < 5; i++) {
            float x = (i + 1) * space + startX;
            float y = height - paddingBottom;
            titlePaint.setColor(Color.parseColor("#ABABAB"));
            titlePaint.setTextAlign(Paint.Align.CENTER);
            canvas.drawText(xTitles[i], x, y, titlePaint);
        }
    }


    private void drawBar(Canvas canvas) {
        float offset = paddingTop + barPaddingStart + scrollY;
        float startX = paddingLeft + maxTitleWidth + titleMarginRight;
        float endX = width - paddingRight - maxValueWidth - valueMarginLeft;
        for (int i = 0; i < titles.length; i++) {
            float y = offset + (2 * i + 1) * 0.5f * barWidth + i * barInterval;
            //画标题
            titlePaint.setTextAlign(Paint.Align.RIGHT);
            titlePaint.setColor(Color.parseColor("#666666"));
            String title = titles[i];
            titlePaint.measureText(title);
            canvas.drawText(title, paddingLeft + maxTitleWidth, y + textSize * 0.5f - titleFontMetrics.bottom, titlePaint);

            //画默认柱形背景
            canvas.drawLine(startX, y, endX, y, barPaint);
            //画进度
            float valueWidth = xWidth * values[i] / 30000f;
            float valueEndX = startX + valueWidth;
            LinearGradient shader = new LinearGradient(startX, y, valueEndX, y, colors, null, Shader.TileMode.CLAMP);
            valueBarPaint.setShader(shader);
            canvas.drawLine(startX, y, valueEndX, y, valueBarPaint);


            //画值
            valuePaint.setTextAlign(Paint.Align.RIGHT);
            valuePaint.setColor(Color.parseColor("#666666"));
            String value = values[i] + "";
            valuePaint.measureText(value);
            canvas.drawText(value, width - paddingRight, y + textSize * 0.5f - valueFontMetrics.bottom, valuePaint);
        }
    }

    private void initMaxTitleWidth() {
        if (titles == null || titles.length == 0) return;
        maxTitleWidth = 0;
        for (String temp : titles) {
            float width = titlePaint.measureText(temp);
            if (width > maxTitleWidth) {
                maxTitleWidth = width;
            }
        }
    }

    private void initMaxValueWidth() {
        if (values == null || values.length == 0) return;
        maxValueWidth = 0;
        for (double temp : values) {
            float width = valuePaint.measureText(String.valueOf(temp));
            if (width > maxValueWidth) {
                maxValueWidth = width;
            }
        }
    }

    //初始化柱状图的总高度
    private void initBarContentHeight() {
        if (values != null && values.length > 0) {
            barTotalHeight = values.length * barWidth + (values.length - 1) * barInterval;
        }
    }

    /**
     * @param direction 标识滑动方向  正数：下滑(手指从下至上移动)；负数：上滑(手指由上向下移动)
     * @return
     */
    @Override
    public boolean canScrollVertically(int direction) {
        if (direction > 0) {
            return barTotalHeight + barPaddingStart + barPaddingEnd - yWidth - Math.abs(scrollY) > 0;
        } else {
            return scrollY < 0;
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                float currentY = event.getY();
                float offset = currentY - lastY;
                if (offset < 0) {//下滑（手指往上滑动）
                    if (canScrollVertically(1)) {
                        scrollY += offset * factor;
                        if (Math.abs(scrollY) >= barTotalHeight + barPaddingStart + barPaddingEnd - yWidth) {
                            scrollY = -(barTotalHeight + barPaddingStart + barPaddingEnd - yWidth);
                        }
                        postInvalidate();
                    }
                }

                if (offset > 0) {//上滑（手指往下滑动）
                    if (canScrollVertically(-1)) {
                        scrollY += offset * factor;
                        if (scrollY >= 0) {
                            scrollY = 0;
                        }
                        postInvalidate();
                    }
                }
                lastY = currentY;
                break;
            case MotionEvent.ACTION_UP:
                lastY = 0;
                break;
        }
        return true;
    }
}